package cn.qayy.utils;

import java.beans.PropertyDescriptor;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.faces.context.FacesContext;
import javax.servlet.ServletContext;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFDataFormat;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.usermodel.HSSFRichTextString;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetProtection;
import org.springframework.web.multipart.MultipartFile;

import cn.qayy.constants.Constant;
import cn.qayy.po.Basis;
import cn.qayy.service.Uploadable;

/**
 * excel 操作工具类 .xls不推荐使用，这里只是学习，推荐使用.csv .xls需要jar包： <!--
 * https://mvnrepository.com/artifact/org.apache.poi/poi --> <dependency>
 * <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId>
 * <version>3.8-beta3</version> </dependency>
 * ------------------------------------------------------------------- .csv不需要
 *
 * @author jobs1127
 */
@SuppressWarnings("all")
public class ExcelUtils {
	private static final Logger logger = Logger.getLogger(ExcelUtils.class);
	public static final int EXCELSHEETSIZE = 65535;
	/***
	 * .xls使用的类
	 */
	protected HSSFWorkbook wb;// Excel工作簿
	private HSSFCellStyle cellStyleTitle;// 标题行样式
	private HSSFCellStyle cellStyleNormal;// 其他行的样式

	/***
	 * 后缀常量
	 */
	private final static String EXCEL2003L = ".xls"; // 2003- 版本的excel
	private final static String EXCEL2007U = ".xlsx"; // 2007+ 版本的excel

	private static ExcelUtils instance = null;
	/**
	 * .xls 初始化工作簿对象，设置首行的字体样式和表格字体样式
	 */
	public ExcelUtils() {
		// 创建工作簿
		wb = new HSSFWorkbook();
		HSSFFont font = wb.createFont();
		font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
		font.setFontName("Verdana");
		font.setFontHeightInPoints((short) 9);
		cellStyleTitle = wb.createCellStyle();
		cellStyleTitle.setFont(font);
		// 表格里字体样式
		font = wb.createFont();
		font.setBoldweight(HSSFFont.BOLDWEIGHT_NORMAL);
		font.setFontName("SimSun");
		font.setFontHeightInPoints((short) 9);
		cellStyleNormal = wb.createCellStyle();
		cellStyleNormal.setFont(font);
	}
	
	
	public static ExcelUtils getInstance() {
		if(instance == null) {
			instance = new ExcelUtils();
		}
		return instance;
	}

	/**
	 * .xls把数据内容写入并生成Excel
	 *
	 * @param list 数据 list.size控制行 firstRowValue.size控制列
	 * @param firstRowValue 标题行数据
	 * @return
	 */
	@Deprecated
	public String dataToExcel(List<Object[]> list, String[] firstRowValue) throws Exception {//TODO
		int listSize = list.size();
		// Excel2003版最大行数是65536行 表单数
		int sheetCount = (listSize - 1) / ExcelUtils.EXCELSHEETSIZE + 1;
		int startRow = 0, endRow = 0;
		boolean aok = false;
		boolean aI = false;
		for (int i = 1; i <= sheetCount; i++) {
			HSSFSheet sheet = wb.createSheet("Sheet" + i);
			HSSFRow row = sheet.createRow(0);
			for (int j = 0; j < firstRowValue.length; j++) {
				HSSFCell cell = row.createCell(j);
				String a = firstRowValue[j];
				try {
					Float.parseFloat(a);
				} catch (NumberFormatException e) {
					aok = true;
				}
				if (aok) {
					cell.setCellValue(new HSSFRichTextString(a));
					aok = false;
					cell.setCellStyle(cellStyleTitle);
				} else {
					try {
						Integer.parseInt(a);
					} catch (NumberFormatException e) {
						aI = true;
					}
					if (aI) {
						Float numv = Float.parseFloat(a);
						cell.setCellValue(numv);
						HSSFCellStyle cellStyle = wb.createCellStyle();
						cellStyle.setDataFormat(HSSFDataFormat.getBuiltinFormat("0.00"));
						cellStyle.setLocked(false);
						cell.setCellStyle(cellStyle);
						aI = false;
					} else {
						Float numv = Float.parseFloat(a);
						cell.setCellValue(numv);
						cell.setCellType(HSSFCell.CELL_TYPE_NUMERIC);
					}
				}
			}
			startRow = (i - 1) * ExcelUtils.EXCELSHEETSIZE;
			endRow = Math.min(startRow + ExcelUtils.EXCELSHEETSIZE - 1, listSize - 1);
			for (int j = startRow; j <= endRow; j++) {
				Object[] obj = list.get(j);
				row = sheet.createRow(j % ExcelUtils.EXCELSHEETSIZE + 1);
				for (int k = 0; k < obj.length; k++) {
					HSSFCell cell = row.createCell(k);
					String a = obj[k].toString();
					try {
						Float.parseFloat(a);
					} catch (NumberFormatException e) {
						aok = true;
					}
					if (aok) {
						cell.setCellValue(new HSSFRichTextString(a));
						aok = false;
						cell.setCellStyle(cellStyleNormal);
					} else if (Float.parseFloat(a) > 2147483647) {
						cell.setCellValue(new HSSFRichTextString(a));
						aok = false;
						cell.setCellStyle(cellStyleNormal);
					} else {
						try {
							Integer.parseInt(a);
						} catch (NumberFormatException e) {
							aI = true;
						}
						if (aI) {
							Float numv = Float.parseFloat(a);
							cell.setCellValue(numv);
							HSSFCellStyle cellStyle = wb.createCellStyle();
							cellStyle.setDataFormat(HSSFDataFormat.getBuiltinFormat("0.00"));
							cellStyle.setLocked(false);
							cell.setCellStyle(cellStyle);
							aI = false;
						} else {
							Float numv = Float.parseFloat(a);
							cell.setCellValue(numv);
							cell.setCellType(HSSFCell.CELL_TYPE_NUMERIC);
						}
					}
				}
			}
		}
		String realname = createFile();
		FileOutputStream fout = new FileOutputStream(realname);
		// 文件输出流，参数如果是：String，指定对应的路径即可
		wb.write(fout);
		fout.flush();
		fout.close();
		return realname;
	}
	
	
	/**
	 * 数据生成excel .xls
	 *
	 * @param filePath 保存路径
	 * @param sheetName sheet标题
	 * @param title 列标题
	 * @param dataSet 数据
	 */
	public static String dataToExcelDxls(String sheetName,String[] title, List<?> dataSet) throws Exception {
		// 创建一个webbook
		HSSFWorkbook wb = new HSSFWorkbook();
		HSSFFont font = wb.createFont();
		font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
		font.setFontName("Verdana");
		font.setFontHeightInPoints((short) 9);
		HSSFCellStyle cellStyleTitle = wb.createCellStyle();
		cellStyleTitle.setFont(font);
		// 表格里字体样式
		font = wb.createFont();
		font.setBoldweight(HSSFFont.BOLDWEIGHT_NORMAL);
		font.setFontName("SimSun");
		font.setFontHeightInPoints((short) 9);
		HSSFCellStyle cellStyleNormal = wb.createCellStyle();
		cellStyleNormal.setFont(font);
		//cellStyleNormal.setWrapText(true);
		// 添加一个sheet，并取名为sheetName对应的名字
		HSSFSheet sheet = wb.createSheet(sheetName);
		// sheet中添加表头，下标为0的行，即第一行
		HSSFRow row = sheet.createRow((int) 0);
		// 创建单元格，并设置值表头 设置表头居中
		//HSSFCellStyle style = wb.createCellStyle();
		//style.setAlignment(HSSFCellStyle.ALIGN_CENTER); // 创建一个居中格式
		// 列
		HSSFCell cell = null;
		for (int i = 0; i < title.length; i++) {
			cell = row.createCell(i);
			cell.setCellStyle(cellStyleTitle);
			cell.setCellValue(title[i]);
		}
		// 填充数据
		Field[] fields = null;
		boolean aok = false;
		boolean aI = false;
		int i = 1;
		HSSFCellStyle cellStyle = wb.createCellStyle();
		/**
		 * 方式1 若暂时不知道dataSet里的数据，也就是说dataSet这个数据还没准备好，我就开始写这里的程序了， 这时可以通过反射来完成。
		 */
		for (Object obj : dataSet) {
			fields = obj.getClass().getDeclaredFields();
			int j = 0;
			row = sheet.createRow((int) i);
			for (Field filed : fields) {
				// filed为private的如果要使用该private的属性，则需要设置可以访问
				filed.setAccessible(true);
				Object val = filed.get(obj);
				val = (null == val ? "" : val);
				cell = row.createCell((int) j);
				cell.setCellStyle(cellStyleNormal);
				Boolean isNum = false;//data是否为数值型
                Boolean isInteger=false;//data是否为整数
                Boolean isPercent=false;//data是否为百分数
                if (val != null || "".equals(val)) {
                    //判断data是否为数值型
                    isNum = val.toString().matches("^(-?\\d+)(\\.\\d+)?$");
                    //判断data是否为整数（小数部分是否为0）
                    isInteger=val.toString().matches("^[-\\+]?[\\d]*$");
                    //判断data是否为百分数（是否包含“%”）
                    isPercent=val.toString().contains("%");
                }
              //如果单元格内容是数值类型，涉及到金钱（金额、本、利），则设置cell的类型为数值型，设置data的类型为数值类型
                if (isNum && !isPercent) {
                    HSSFDataFormat df = wb.createDataFormat(); // 此处设置数据格式
                    if (isInteger) {
                        cellStyleNormal.setDataFormat(df.getBuiltinFormat("#,#0"));//数据格式只显示整数
                    }else{
                        cellStyleNormal.setDataFormat(df.getBuiltinFormat("#,##0.00"));//保留两位小数点
                    }                   
                    // 设置单元格格式
                    cell.setCellStyle(cellStyleNormal);
                    // 设置单元格内容为double类型
                    cell.setCellValue(Double.parseDouble(val.toString()));
                } else {
                    cell.setCellStyle(cellStyleNormal);
                    // 设置单元格内容为字符型
                    cell.setCellValue(val.toString());
                }
				j++;
			}
			i++;
		}
		// 保存excel文件到指定路径
		String filePath = createFile();
		FileOutputStream fout = new FileOutputStream(filePath);
		wb.write(fout);
		fout.flush();
		fout.close();
		return filePath;
	}
	/**
	 * 数据生成excel .xls
	 *
	 * @param filePath 保存路径
	 * @param sheetName sheet标题
	 * @param title 列标题
	 * @param dataSet 数据
	 */
	public static String taskToExcelDxls(String sheetName,String[] title, List<?> dataSet) throws Exception {
		// 创建一个webbook
		HSSFWorkbook wb = new HSSFWorkbook();
		HSSFFont font = wb.createFont();
		font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
		font.setFontName("Verdana");
		font.setFontHeightInPoints((short) 9);
		HSSFCellStyle cellStyleTitle = wb.createCellStyle();
		
		HSSFCellStyle cellStyleEdit = wb.createCellStyle();
		cellStyleEdit.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);  //填充单元格
		cellStyleEdit.setFillForegroundColor(HSSFColor.RED.index);    //填红色
		
		cellStyleTitle.setFont(font);
		// 表格里字体样式
		font = wb.createFont();
		font.setBoldweight(HSSFFont.BOLDWEIGHT_NORMAL);
		font.setFontName("SimSun");
		font.setFontHeightInPoints((short) 9);
		HSSFCellStyle cellStyleNormal = wb.createCellStyle();
		cellStyleNormal.setFont(font);
		cellStyleNormal.setWrapText(true);
		// 添加一个sheet，并取名为sheetName对应的名字
		HSSFSheet sheet = wb.createSheet(sheetName);
		//sheet.setAutoFilter(CellRangeAddress.valueOf("A1:AD"));
		//sheet.protectSheet("jobs1127");
		//单元格锁定的样式
		HSSFCellStyle unLockCellStyle = wb.createCellStyle();
		unLockCellStyle.setLocked(false);
		// sheet中添加表头，下标为0的行，即第一行
		HSSFRow row = sheet.createRow((int) 0);
		// 创建单元格，并设置值表头 设置表头居中
		//HSSFCellStyle style = wb.createCellStyle();
		//style.setAlignment(HSSFCellStyle.ALIGN_CENTER); // 创建一个居中格式
		// 列
		HSSFCell cell = null;
		for (int i = 0; i < title.length; i++) {
			cell = row.createCell(i);
			cell.setCellStyle(cellStyleTitle);
			cell.setCellStyle(unLockCellStyle);
			if(i == 11 || i==12 || i==17 || i==18 || i==19 || i==21 || i==22 || i==23 || i==26 || i==27) {
				cell.setCellStyle(cellStyleEdit);
			}
			cell.setCellValue(title[i]);
		}
		// 填充数据
		Field[] fields = null;
		boolean aok = false;
		boolean aI = false;
		int i = 1;
		HSSFCellStyle cellStyle = wb.createCellStyle();
		
	
		/**
		 * 方式1 若暂时不知道dataSet里的数据，也就是说dataSet这个数据还没准备好，我就开始写这里的程序了， 这时可以通过反射来完成。
		 */
		for (Object obj : dataSet) {
			fields = obj.getClass().getDeclaredFields();
			int j = 0;
			row = sheet.createRow((int) i);
			for (Field filed : fields) {
				// filed为private的如果要使用该private的属性，则需要设置可以访问
				filed.setAccessible(true);
				Object val = filed.get(obj);
				val = (null == val ? "" : val);
				cell = row.createCell((int) j);
				
				if(j == 11 || j==12 || j==17 || j==18 || j==19 || j==21 || j==22 || j==23 || j==26 || j==27) {
					cell.setCellStyle(unLockCellStyle);
				} else {
					cell.setCellStyle(cellStyleNormal);
				}
				Boolean isNum = false;//data是否为数值型
				Boolean isInteger=false;//data是否为整数
				Boolean isPercent=false;//data是否为百分数
				if (val != null || "".equals(val)) {
					//判断data是否为数值型
					isNum = val.toString().matches("^(-?\\d+)(\\.\\d+)?$");
					//判断data是否为整数（小数部分是否为0）
					isInteger=val.toString().matches("^[-\\+]?[\\d]*$");
					//判断data是否为百分数（是否包含“%”）
					isPercent=val.toString().contains("%");
				}
				//如果单元格内容是数值类型，涉及到金钱（金额、本、利），则设置cell的类型为数值型，设置data的类型为数值类型
				if (isNum && !isPercent) {
					HSSFDataFormat df = wb.createDataFormat(); // 此处设置数据格式
					if (isInteger) {
						cellStyleNormal.setDataFormat(df.getBuiltinFormat("#,#0"));//数据格式只显示整数
					}else{
						cellStyleNormal.setDataFormat(df.getBuiltinFormat("#,##0.00"));//保留两位小数点
					}                   
					// 设置单元格格式
					if(j == 11 || j==12 || j==17 || j==18 || j==19 || j==21 || j==22 || j==23 || j==26 || j==27) {
						cell.setCellStyle(unLockCellStyle);
					} else {
						cell.setCellStyle(cellStyleNormal);
					}
					// 设置单元格内容为double类型
					cell.setCellValue(Double.parseDouble(val.toString()));
				} else {
					if(j == 11 || j==12 || j==17 || j==18 || j==19 || j==21 || j==22 || j==23 || j==26 || j==27) {
						cell.setCellStyle(unLockCellStyle);
					} else {
						cell.setCellStyle(cellStyleNormal);
					}
					// 设置单元格内容为字符型
					cell.setCellValue(val.toString());
				}
				j++;
			}
			i++;
		}
		
		// 保存excel文件到指定路径
		String filePath = createFile();
		FileOutputStream fout = new FileOutputStream(filePath);
		wb.write(fout);
		fout.flush();
		fout.close();
		return filePath;
	}
	
	public static String dataToExcelDxls_bak2(String sheetName,String[] title, List<?> dataSet) throws Exception {
		// 创建一个webbook
		HSSFWorkbook wb = new HSSFWorkbook();
		HSSFFont font = wb.createFont();
		font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
		font.setFontName("Verdana");
		font.setFontHeightInPoints((short) 9);
		HSSFCellStyle cellStyleTitle = wb.createCellStyle();
		cellStyleTitle.setFont(font);
		// 表格里字体样式
		font = wb.createFont();
		font.setBoldweight(HSSFFont.BOLDWEIGHT_NORMAL);
		font.setFontName("SimSun");
		font.setFontHeightInPoints((short) 9);
		HSSFCellStyle cellStyleNormal = wb.createCellStyle();
		cellStyleNormal.setFont(font);
		//cellStyleNormal.setWrapText(true);
		// 添加一个sheet，并取名为sheetName对应的名字
		HSSFSheet sheet = wb.createSheet(sheetName);
		// sheet中添加表头，下标为0的行，即第一行
		HSSFRow row = sheet.createRow((int) 0);
		// 创建单元格，并设置值表头 设置表头居中
		//HSSFCellStyle style = wb.createCellStyle();
		//style.setAlignment(HSSFCellStyle.ALIGN_CENTER); // 创建一个居中格式
		// 列
		HSSFCell cell = null;
		for (int i = 0; i < title.length; i++) {
			cell = row.createCell(i);
			cell.setCellStyle(cellStyleTitle);
			cell.setCellValue(title[i]);
		}
		HSSFDataFormat format = wb.createDataFormat();
		
		// 填充数据
		Field[] fields = null;
		boolean aok = false;
		boolean aI = false;
		int i = 1;
		HSSFCellStyle cellStyle = wb.createCellStyle();
		/**
		 * 方式1 若暂时不知道dataSet里的数据，也就是说dataSet这个数据还没准备好，我就开始写这里的程序了， 这时可以通过反射来完成。
		 */
		for (Object obj : dataSet) {
			fields = obj.getClass().getDeclaredFields();
			int j = 0;
			row = sheet.createRow((int) i);
			for (Field filed : fields) {
				// filed为private的如果要使用该private的属性，则需要设置可以访问
				filed.setAccessible(true);
				Object val = filed.get(obj);
				val = (null == val ? "" : val);
				cell = row.createCell((int) j);
				cell.setCellStyle(cellStyleNormal);
				String strVal = val+"";
				try {
					Float.parseFloat(strVal);
				} catch (NumberFormatException e) {
					aok = true;
				}
				if (aok) {
					cell.setCellValue(new HSSFRichTextString(strVal));
					aok = false;
					cell.setCellStyle(cellStyleNormal);
				} else if (Float.parseFloat(strVal) > 2147483647) {
					cell.setCellValue(new HSSFRichTextString(strVal));
					aok = false;
					cell.setCellStyle(cellStyleNormal);
				} else {
					try {
						Integer.parseInt(strVal);
					} catch (NumberFormatException e) {
						aI = true;
					}
					if (aI) {
//						Float numv = Float.parseFloat(strVal);
//						cell.setCellValue(numv);
//						cellStyle.setDataFormat(HSSFDataFormat.getBuiltinFormat("0.00"));
//						cellStyle.setLocked(false);
//						cell.setCellStyle(cellStyle);
//						aI = false;
						
						cellStyle.setDataFormat(format.getFormat("@")); 
						cell.setCellValue(new HSSFRichTextString(strVal));
						cell.setCellStyle(cellStyle);
						aok = false;
						cell.setCellStyle(cellStyleNormal);
					} else {
						//Float numv = Float.parseFloat(strVal);
						Long numv = Long.parseLong(strVal);
						cell.setCellValue(numv);
						cell.setCellType(HSSFCell.CELL_TYPE_NUMERIC);
					}
				}
				j++;
			}
			i++;
		}
		// 保存excel文件到指定路径
		String filePath = createFile();
		FileOutputStream fout = new FileOutputStream(filePath);
		wb.write(fout);
		fout.flush();
		fout.close();
		return filePath;
	}
	
	
	
	
	public static String dataToExcelDxls_bak(String sheetName,String[] title, List<?> dataSet) throws Exception {
		// 创建一个webbook
		HSSFWorkbook wb = new HSSFWorkbook();
		HSSFFont font = wb.createFont();
		font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
		font.setFontName("Verdana");
		font.setFontHeightInPoints((short) 9);
		HSSFCellStyle cellStyleTitle = wb.createCellStyle();
		cellStyleTitle.setFont(font);
		// 表格里字体样式
		font = wb.createFont();
		font.setBoldweight(HSSFFont.BOLDWEIGHT_NORMAL);
		font.setFontName("SimSun");
		font.setFontHeightInPoints((short) 9);
		HSSFCellStyle cellStyleNormal = wb.createCellStyle();
		cellStyleNormal.setFont(font);
		// 添加一个sheet，并取名为sheetName对应的名字
		HSSFSheet sheet = wb.createSheet(sheetName);
		// sheet中添加表头，下标为0的行，即第一行
		HSSFRow row = sheet.createRow((int) 0);
		// 创建单元格，并设置值表头 设置表头居中
		//HSSFCellStyle style = wb.createCellStyle();
		//style.setAlignment(HSSFCellStyle.ALIGN_CENTER); // 创建一个居中格式
		// 列
		HSSFCell cell = null;
		for (int i = 0; i < title.length; i++) {
			cell = row.createCell(i);
			cell.setCellStyle(cellStyleTitle);
			cell.setCellValue(title[i]);
		}
		// 填充数据
		Field[] fields = null;
		int i = 1;
		/**
		 * 方式1 若暂时不知道dataSet里的数据，也就是说dataSet这个数据还没准备好，我就开始写这里的程序了， 这时可以通过反射来完成。
		 */
		for (Object obj : dataSet) {
			fields = obj.getClass().getDeclaredFields();
			int j = 0;
			row = sheet.createRow((int) i);
			for (Field filed : fields) {
				// filed为private的如果要使用该private的属性，则需要设置可以访问
				filed.setAccessible(true);
				Object val = filed.get(obj);
				val = (null == val ? "" : val);
				HSSFCell c = row.createCell((int) j);
				c.setCellStyle(cellStyleNormal);
				c.setCellType(HSSFCell.CELL_TYPE_STRING);
				String strVal = val+"";
				c.setCellValue(strVal);
				j++;
			}
			i++;
		}
		// 保存excel文件到指定路径
		String filePath = createFile();
		FileOutputStream fout = new FileOutputStream(filePath);
		wb.write(fout);
		fout.flush();
		fout.close();
		return filePath;
	}

	/**
	 * .cvs 从服务器下载到本地
	 *
	 * @param response
	 * @param realname
	 * @throws IOException
	 */
	public static void downloadExcel(ServletContext servletContext,HttpServletResponse response, String realname) {
		System.out.println("downloadExcel...");
		InputStream is = null;
		ServletOutputStream out = null;
		File f = null;
		try {
			f = new File(realname);
			String fileName = f.getName();
			/**
			 * 要实现客户端有下载的对话框，这里需要设置response的类型为application/x-msdownload
			 */
			//String contentType = "application/x-download";
			//response.setContentType(contentType);
			
			//1.设置文件的mimeType
			String mimeType = servletContext.getMimeType(fileName);
			response.setContentType(mimeType);
			//2.网络上的方式 (8成好使)
			response.setHeader("Content-Disposition",
					"attachment;filename=" + new String(fileName.getBytes("gb2312"), "ISO8859-1"));
			// 为了让https能够下载
			//response.setHeader("Expires", "0");
			//response.setHeader("Pragma", "public");
			//response.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0");
			//response.setHeader("Cache-Control", "public");
			// HttpServletRequest request = (HttpServletRequest)
			// FacesContext.getCurrentInstance().getExternalContext().getRequest();
			
			out = response.getOutputStream();
			is = new FileInputStream(f);
			
			/**
			 * 3.自己写的管道
			 */
			/****/
			byte[] bytes = new byte[0xffff];
			is = new FileInputStream(new File(realname));
			int b = 0;
			while ((b = is.read(bytes, 0, 0xffff)) > 0) {
				out.write(bytes, 0, b);
			}
			
			//3.对拷流
			//IOUtils.copy(is, out); 
			
		} catch (Exception e) {
			System.out.println("------------------11111111111111111111111-----------");
			e.printStackTrace();
		} finally {
			try {
				if (is != null) {
					is.close();
				}
				if (out != null) {
					//out.flush();这句话千万别加，如果数据量大了，会出现连接错误，您的主机中的软件中止了一个已建立的连接。
					out.close();
				}
				// 该文件让她保存到服务器端，不要删除，删除可能存在导致下载空白的情况。
				// if (f != null) {
				// f.delete();
				// }
			} catch (Exception e) {
				System.out.println("------------------22222222222222222222-----------");
				e.printStackTrace();
			}
		}
	}
	/**
	 * .cvs 从服务器下载到本地
	 *
	 * @param response
	 * @param realname
	 * @throws IOException
	 */
	@Deprecated
	public static void downloadExcel2(HttpServletResponse response, String realname) {
		InputStream is = null;
		ServletOutputStream out = null;
		File f = null;
		try {
			f = new File(realname);
			String fileName = f.getName();
			/**
			 * 要实现客户端有下载的对话框，这里需要设置response的类型为application/x-msdownload
			 */
			String contentType = "application/x-download";
			response.setContentType(contentType);
			response.setHeader("Content-Disposition",
					"attachment;filename=" + new String(fileName.getBytes("gb2312"), "ISO8859-1"));
			// 为了让https能够下载
			//response.setHeader("Expires", "0");
			response.setHeader("Pragma", "public");
			response.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0");
			response.setHeader("Cache-Control", "public");
			// HttpServletRequest request = (HttpServletRequest)
			// FacesContext.getCurrentInstance().getExternalContext().getRequest();
			out = response.getOutputStream();
			byte[] bytes = new byte[0xffff];
			is = new FileInputStream(new File(realname));
			int b = 0;
			while ((b = is.read(bytes, 0, 0xffff)) > 0) {
				out.write(bytes, 0, b);
			}
		} catch (Exception e) {
			// e.printStackTrace();
		} finally {
			try {
				if (is != null) {
					is.close();
				}
				if (out != null) {
					//out.flush();
					out.close();
				}
				// 该文件让她保存到服务器端，不要删除，删除可能存在导致下载空白的情况。
				// if (f != null) {
				// f.delete();
				// }
			} catch (Exception e) {
				// e.printStackTrace();
			}
		}
	}

	/**
	 * 创建文件，把生成的Excle写入到某个路径
	 *
	 * @return
	 */
	public static String createFile() {
		// path表示你所创建文件的路径
		String path = "d:/down_xls/";
		File f = new File(path);
		if (!f.exists()) {
			f.mkdirs();
		}
		// fileName表示你创建的文件名；为txt类型；
		String fileName = System.currentTimeMillis() + ".xls";
		// System.out.println(fileName);
		File file = new File(f, fileName);
		if (!file.exists()) {
			try {
				file.createNewFile();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return path + fileName;
	}

	/**
	 * 自己准备list数据，填充Object[]对象，把准备好的数据传递过来，该方法使用起来比较累，不推荐使用。 导出cvs的格式的Excel .csv
	 *
	 * @param list 带填充到csv文件的数据
	 * @param firstRowValue  第一行的值，即表头
	 * @return
	 */
	@Deprecated
	public static String exportCvsSlef(List<Object[]> list, String[] firstRowValue) {
		List exportData = new ArrayList<Map>();
		Map row = new LinkedHashMap<String, String>();
		for (int i = 0; i < list.size(); i++) {
			Object[] obj = list.get(i);
			for (int j = 0; j < obj.length; j++) {
				row.put(j + 1, obj[j]);
			}
			exportData.add(row);
			row = new LinkedHashMap<String, String>();
		}
		// List propertyNames = new ArrayList();
		LinkedHashMap map = new LinkedHashMap();
		for (int k = 0; k < firstRowValue.length; k++) {
			map.put(k + 1, firstRowValue[k]);
		}
		String realname = "d:/down_xls/";
		String titlename = System.currentTimeMillis() + "";
		createCSVFile(exportData, map, realname, titlename);
		exportData.clear();
		exportData = null;
		row.clear();
		row = null;
		map.clear();
		map = null;
		return realname + titlename + ".csv";
	}

	/**
	 * 通过反射+泛型封装的方法，比较灵活，推荐使用。 导出cvs的格式的Excel .csv //csv文件比.xls文件可读性好，而且下载速度快，推荐使用。
	 *
	 * @param list 带填充到csv文件的数据(数组类型)
	 * @param firstRowValue 第一行的值，即表头(数组类型)
	 * @return 注意因为是使用反射，所以目标下载的list里的对象，对应的类的属性的顺序就是下载后的标题顺序。
	 */
	public static String exportCVS(List<?> list, String[] firstRowValue) {//TODO
		List exportData = new ArrayList<Map>();
		Map row = new LinkedHashMap<String, String>();
		Field[] fields = null;
		for (Object obj : list) {// 所有行循环，该循环完后即填充了所有的记录行
			fields = obj.getClass().getDeclaredFields();
			for (int j = 0; j < fields.length; j++) {// 填充一行
				fields[j].setAccessible(true);
				Object val = null;
				try {
					val = fields[j].get(obj);
				} catch (IllegalAccessException e) {
					e.printStackTrace();
				}
				val = (null == val ? "" : val);
				row.put(j + 1, val);
			}
			exportData.add(row);
			row = new LinkedHashMap<String, String>();
		}
		LinkedHashMap map = new LinkedHashMap();
		// 填充标题行
		for (int k = 0; k < firstRowValue.length; k++) {
			map.put(k + 1, firstRowValue[k]);
		}
		// 文件下载的路径
		String realname = "d:/down_xls/";
		final String titlename = System.currentTimeMillis() + "";
		createCSVFile(exportData, map, realname, titlename);
		exportData.clear();
		exportData = null;
		row.clear();
		row = null;
		map.clear();
		map = null;
		if (fields != null) {
			fields = null;
		}
		return realname + titlename + ".csv";
	}
	
	/**
	 * 没有使用反射的cvs的方式
	 * @param list
	 * @param firstRowValue
	 * @return
	 */
	public String exportCvsNoReflection(List<Object[]> list, String[] firstRowValue){
		List exportData = new ArrayList<Map>();  
        Map row = new LinkedHashMap<String, String>();
		for(int i=0;i<list.size();i++){
			Object[] obj = list.get(i);
			for(int j=0;j<obj.length;j++){
				row.put(j+1, obj[j]);
			}
			 exportData.add(row);
			 row = new LinkedHashMap<String, String>(); 
		}
		
		List propertyNames = new ArrayList();  
	    LinkedHashMap map = new LinkedHashMap();
	    for(int k=0;k<firstRowValue.length;k++){
	    	map.put(k+1,firstRowValue[k]);
	    }
	    String realname = "d:/down_xls/";
	    String titlename = System.currentTimeMillis()+"";
	    createCSVFile(exportData, map, realname, titlename);
		return realname+titlename+".csv";
	}
	/***
	 * 创建CSV文件
	 * 
	 * @param exportData
	 *            准备好的数据
	 * @param rowMapper
	 *            准备好的表头数据
	 * @param outPutPath
	 *            文件的保存路径
	 * @param filename
	 *            文件名
	 * @return
	 */
	private static File createCSVFile(List exportData, LinkedHashMap rowMapper, String outPutPath, String filename) {
		File csvFile = null;
		BufferedWriter csvFileOutputStream = null;
		try {
			// 构建csv文件路径和文件名
			csvFile = new File(outPutPath + filename + ".csv");
			// 路径不存在则创建
			File parent = csvFile.getParentFile();
			if (parent != null && !parent.exists()) {
				parent.mkdirs();
			}
			// 创建csv文件
			csvFile.createNewFile();
			// GB2312使正确读取分隔符","
			csvFileOutputStream = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(csvFile), "GBK"),
					1024);
			// 写入文件头部
			for (Iterator propertyIterator = rowMapper.entrySet().iterator(); propertyIterator.hasNext();) {
				Map.Entry propertyEntry = (Map.Entry) propertyIterator.next();
				csvFileOutputStream.write("\"" + propertyEntry.getValue().toString() + "\"");
				if (propertyIterator.hasNext()) {
					csvFileOutputStream.write(",");
				}
			}
			csvFileOutputStream.newLine();
			// 写入文件内容
			for (Iterator iterator = exportData.iterator(); iterator.hasNext();) {
				// Object row = (Object) iterator.next();
				LinkedHashMap row = (LinkedHashMap) iterator.next();
				for (Iterator propertyIterator = row.entrySet().iterator(); propertyIterator.hasNext();) {
					Map.Entry propertyEntry = (Map.Entry) propertyIterator.next();
					csvFileOutputStream.write("\"" + propertyEntry.getValue().toString() + "\"");
					if (propertyIterator.hasNext()) {
						csvFileOutputStream.write(",");
					}
				}
				if (iterator.hasNext()) {
					csvFileOutputStream.newLine();
				}
			}
			csvFileOutputStream.flush();
		} catch (Exception e) {
			// e.printStackTrace();
		} finally {
			try {
				csvFileOutputStream.close();
			} catch (IOException e) {
				// e.printStackTrace();
			}
		}
		return csvFile;
	}

	/**
	 * Excel导入
	 */
	public static List<List<Object>> getBankListByExcel(InputStream in, String fileName) throws Exception {
		List<List<Object>> list = null;
		// 创建Excel工作薄
		// System.out.println("进入getBankListByExcel....");
		// System.out.println("fileType:" + fileName);
		Workbook work = getWorkbook(in, fileName);

		if (null == work) {
			throw new Exception("创建Excel工作薄为空！");
		}
		Sheet sheet = null;
		Row row = null;
		Cell cell = null;
		list = new ArrayList<List<Object>>();
		// 遍历Excel中所有的sheet
		for (int i = 0; i < work.getNumberOfSheets(); i++) {
			sheet = work.getSheetAt(i);
			if (sheet == null) {
				continue;
			}
			// 遍历当前sheet中的所有行
			// 包涵头部，所以要小于等于最后一列数,这里也可以在初始值加上头部行数，以便跳过头部
			for (int j = sheet.getFirstRowNum(); j <= sheet.getLastRowNum(); j++) {
				// 读取一行
				row = sheet.getRow(j);
				// 去掉空行和表头
				if (row == null || row.getFirstCellNum() == j) {
					continue;
				}
				// 遍历所有的列
				List<Object> li = new ArrayList<Object>();
				for (int y = 0; y < 4; y++) { // 由于个人原因被明确规定了导入数据只有三列，
					cell = row.getCell(y); // 且 考虑到导入的excel单元格内可以不写东西得情况
					if (cell == null) // 所以直接用 明确的数值来确定遍历的次数
					{
						li.add(null);
					} // 这里添加了单元格中空白的判断，如果空白默认赋值为null,避免后面mybatis里面出现错误
					else
						li.add(getCellValue(cell));
				}
				list.add(li);
			}
		}
		return list;
	}

	/**
	 * 描述：根据文件后缀，自适应上传文件的版本
	 */
	public static Workbook getWorkbook(InputStream inStr, String fileName) throws Exception {
		System.out.println("进入getWorkbook....");
		Workbook wb = null;
		String fileType = fileName.substring(fileName.lastIndexOf("."));
		System.out.println("fileType：" + fileType);
		if (EXCEL2003L.equals(fileType)) {
			wb = new HSSFWorkbook(inStr); // 2003-
		} else if (EXCEL2007U.equals(fileType)) {
			wb = new XSSFWorkbook(inStr); // 2007+
		} else {
			throw new Exception("解析的文件格式有误！");
		}
		return wb;
	}

	/**
	 * 描述：对表格中数值进行格式化
	 */
	public static Object getCellValue(Cell cell) {
		Object value = null;
		DecimalFormat df = new DecimalFormat("0"); // 格式化字符类型的数字
		SimpleDateFormat sdf = new SimpleDateFormat("yyy-MM-dd"); // 日期格式化
		DecimalFormat df2 = new DecimalFormat("0.00"); // 格式化数字
		switch (cell.getCellType()) {
		case Cell.CELL_TYPE_STRING:
			value = cell.getRichStringCellValue().getString();
			break;
		case Cell.CELL_TYPE_NUMERIC:
			if ("General".equals(cell.getCellStyle().getDataFormatString())) {
				value = df.format(cell.getNumericCellValue());
			} else if ("m/d/yy".equals(cell.getCellStyle().getDataFormatString())) {
				value = sdf.format(cell.getDateCellValue());
			} else {
				value = df2.format(cell.getNumericCellValue());
			}
			break;
		case Cell.CELL_TYPE_BOOLEAN:
			value = cell.getBooleanCellValue();
			break;
		case Cell.CELL_TYPE_BLANK:
			value = "";
			break;
		default:
			break;
		}
		return value;
	}

	/***
	 * 把Excel数据转换成List
	 * 
	 * @param file 上传的文件，获取文件的inputStream输入流，通过workbook封装Excel对象，
	 * 一行一行读取Excel文件，通过反射把Excel行、列封装成目标对象
	 * @param beanclazz 字节码对象,calzz字节码对象newInstance获得Object，把Excel行、列填充到该Object里。
	 * 通过反射，字节码对象获取定义的属性，遍历属性、获取属性名、通过属性名和字节码对象，可以构建属性描述器对象，通过属性描述器对象，
	 * 可以获取对属性的读方法、写方法，通过写方法在Object对象上调用，初始化对象。
	 * @param titleExist 是否是标题行
	 * @return
	 */
	public static List<Uploadable> ExcelForList(MultipartFile file, Class beanclazz, Boolean titleExist)
			throws Exception {
		List<Uploadable> list = new ArrayList<Uploadable>(Constant.CENTER_CAPACITY);
		// IO流读取文件
		InputStream input = file.getInputStream();
		String fileName = file.getOriginalFilename();
		String fileType = fileName.substring(fileName.indexOf(".") + 1);
		Workbook wb = null;
		// 根据文件类型创建文档
		if ("xls".equals(fileType)) {
			wb = new HSSFWorkbook(input); // 2003-
		} else if ("xlsx".equals(fileType)) {
			wb = new XSSFWorkbook(input); // 2007+
		} else {
			throw new Exception("解析的文件格式有误！");
		}
		Sheet sheet = wb.getSheetAt(0);
		// 得到第一张工作表
		int i;
		if (titleExist) {
			i = 1;
		} else {
			i = 0;
		}
		// 行的遍历
		for (; i <= sheet.getLastRowNum(); i++) {
			// 得到行
			Row row = sheet.getRow(i);
			if(row == null) {
				break;
			}
			// 单元格（列）的遍历
			// 实例化对象
			Object object = beanclazz.newInstance();
			
			Field[] fields = beanclazz.getDeclaredFields();
			int j = 0;
			/***
			 * 遍历属性，遍历列，每一个属性通过Excel列来初始化。
			 */
			for (Field field : fields) {
				String fieldName = field.getName();
				PropertyDescriptor pd = new PropertyDescriptor(fieldName, beanclazz);
				Method getMethod = pd.getWriteMethod();
				Cell cell = row.getCell(j++);
				int type = 1;
				if (cell != null) {// cell获取不到，则不对属性进行初始化，使用属性默认值。
					type = cell.getCellType();
					if (type == cell.CELL_TYPE_BOOLEAN) {
						// 返回布尔类型的值
						boolean value = cell.getBooleanCellValue();
						String v = value + "";
						getMethod.invoke(object, v);
					} else if (type == cell.CELL_TYPE_NUMERIC) {
						short format = cell.getCellStyle().getDataFormat();
						SimpleDateFormat sdf = null;
						boolean isDate = false;
						String DateFm = "";
						String noDateFm = "";
						if (format == 14 || format == 31 || format == 57 || format == 58
								|| (176 <= format && format <= 178) || (182 <= format && format <= 196)
								|| (210 <= format && format <= 213) || (208 == format)) { // 日期
							sdf = new SimpleDateFormat("yyyy/MM/dd");
							isDate = true;
						} else { // 不是日期格式，转成字符串
							cell.setCellType(Cell.CELL_TYPE_STRING); 
							isDate = false;
						}
						if(isDate) {
							double value = cell.getNumericCellValue();
							Date date = org.apache.poi.ss.usermodel.DateUtil.getJavaDate(value);
							if (date == null || "".equals(date)) {
								DateFm="";	
							} else {
								DateFm = sdf.format(date);
							}
							getMethod.invoke(object, DateFm);	
						} else {
							String value = cell.getStringCellValue();
							getMethod.invoke(object, value);
						}
					} else if (type == cell.CELL_TYPE_STRING) {
						// 返回字符串类型的值
						String value = cell.getStringCellValue();
						getMethod.invoke(object, value);
					}
				}
			}
			/***
			 * 所有上传的对象，把其封装成接口，接口里定义方法，这样保障了不同模块的对象，都可以调用相同的方法，具体实现，交给具体的实现者去完成。
			 */
			Uploadable uploadable = (Uploadable) object;
			if (list != null) {
				list.add(uploadable);
			}
		}
		return list;
	}

	/**
	 * @描述：是否是2003的excel，返回true是2003
	 * @param filePath
	 * @return
	 */
	public static boolean isExcel2003(String filePath) {
		return filePath.matches("^.+\\.(?i)(xls)$");
	}

	/**
	 * @描述：是否是2007的excel，返回true是2007
	 * @param filePath
	 * @return
	 */
	public static boolean isExcel2007(String filePath) {
		return filePath.matches("^.+\\.(?i)(xlsx)$");
	}

	/**
	 * 验证是否是EXCEL文件
	 * 
	 * @param filePath
	 * @return
	 */
	public static boolean validateExcel(String filePath) {
		if (filePath == null || !(isExcel2003(filePath) || isExcel2007(filePath))) {
			return false;
		}
		return true;
	}
	public void downloadExcel(String realname) throws IOException {
		File f = new File(realname);
		String fileName = f.getName();
		FacesContext ctx = FacesContext.getCurrentInstance();
		String contentType = "application/x-download";
		HttpServletResponse response = (HttpServletResponse) ctx
				.getExternalContext().getResponse();
		response.setContentType(contentType);
		response.setHeader("Content-Disposition", "attachment;filename="
				+ new String(fileName.getBytes("gb2312"), "ISO8859-1"));
		HttpServletRequest request = (HttpServletRequest) FacesContext
				.getCurrentInstance().getExternalContext().getRequest();

		ServletOutputStream out = response.getOutputStream();

		byte[] bytes = new byte[0xffff];
		InputStream is = new FileInputStream(new File(realname));
		int b = 0;
		while ((b = is.read(bytes, 0, 0xffff)) > 0) {
			out.write(bytes, 0, b);
		}
		is.close();
		out.flush();
		ctx.responseComplete();
		f.delete();
	}
	public static String testDown() {
		try {
			String[] rowTitle = {"经理","大区", "片区","省份","地市","区县", "分组标识",
					"修订标识","ID列(请勿动)"};
			
			List<Basis> lists = new ArrayList<Basis>();
			Basis b = new Basis();
			b.setMgr("唐京");
			b.setSpace("细节");
			lists.add(b);
			String realname = ExcelUtils.getInstance().dataToExcelDxls("基础库",rowTitle,lists);
			return realname;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
}